package org.csc.sss.core.repository.impl;

import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;
import org.csc.sss.core.dto.PersonDTO;
import org.csc.sss.core.model.Person;
import org.csc.sss.core.model.SysUser;
import org.csc.sss.core.repository.base.BaseRepositoryImpl;
import org.csc.sss.core.vo.PersonSysUserVO;
import org.hibernate.jpa.criteria.CriteriaBuilderImpl;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.persistence.TypedQuery;
import javax.persistence.criteria.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Service
public class PersonRepositoryImpl extends BaseRepositoryImpl {
	
	public List<PersonSysUserVO> a(){
		String sql = "SELECT new org.csc.sss.core.vo.PersonSysUserVO(p,u) FROM Person p, SysUser u where p.sysUser.id = u.id";
//		String sql = "SELECT p.*,u.nickname FROM person p LEFT JOIN sys_user u ON p.user_id = u.id";
		TypedQuery<PersonSysUserVO> createQuery = super.entityManager.createQuery(sql, PersonSysUserVO.class);
//		Query createQuery = this.entityManager.createQuery(upsql);
//		Query createNativeQuery = entityManager.createNativeQuery(sql, Person.class);
//		List<Person> resultList = createQuery.getResultList();
		return createQuery.getResultList();
	}

	/**
	 * 默认是根据id更新(更新字段需要完善)
	 * @param dto
	 * @return
	 */
	@Transactional
	public int test(PersonDTO dto) {
		List<Predicate> predicates = new ArrayList<Predicate>();
		CriteriaBuilder cb = super.entityManager.getCriteriaBuilder();
		CriteriaUpdate<Person> cu = cb.createCriteriaUpdate(Person.class);
		Root<Person> root = cu.from(Person.class);
		cu.set(Person.ADDRESS, dto.getAddress());
		predicates.add(cb.equal(root.get(Person.ID), dto.getId()));
		Predicate[] pre = new Predicate[predicates.size()];
		cu.where(predicates.toArray(pre));
		return super.entityManager.createQuery(cu).executeUpdate();
	}

	/**
	 * 默认是根据id更新(更新字段需要完善)
	 * @param model
	 * @return
	 */
	@Transactional
	public Boolean update(Person model) {
		List<Predicate> predicates = new ArrayList<Predicate>();
		CriteriaBuilder cb = super.entityManager.getCriteriaBuilder();
		CriteriaUpdate<Person> cu = cb.createCriteriaUpdate(Person.class);
		Root<Person> root = cu.from(Person.class);
		//更新字段需要完善

		//默认是根据id更新
		cu.set(root.get(Person.LAST_MODIFIED_BY).get(SysUser.ID), super.getUser().getId());
		cu.set(Person.LAST_MODIFIED_TIME, new Date());
		predicates.add(cb.equal(root.get(Person.ID), model.getId()));

		Predicate[] pre = new Predicate[predicates.size()];
		cu.where(predicates.toArray(pre));
		if (super.entityManager.createQuery(cu).executeUpdate() > 0) {
			return true;
		}

		return false;
	}

	public List<Person> aaa() {
		CriteriaBuilder cb = super.entityManager.getCriteriaBuilder();
		CriteriaQuery<Person> query = cb.createQuery(Person.class);
		Root<Person> root = query.from(Person.class);


		return super.entityManager.createQuery(query).getResultList();

	}

	/**
	 * 默认是根据id更新(更新字段需要完善)
	 * @param dto
	 * @return
	 */
	@Transactional
	public Boolean update(PersonDTO dto) {
		List<Predicate> predicates = new ArrayList<Predicate>();
		CriteriaBuilder cb = super.entityManager.getCriteriaBuilder();
		CriteriaUpdate<Person> cu = cb.createCriteriaUpdate(Person.class);
		Root<Person> root = cu.from(Person.class);
		//更新字段需要完善
		cu.set(Person.ADDRESS, dto.getAddress());

		//默认是根据id更新
		cu.set(root.get(Person.LAST_MODIFIED_BY).get(SysUser.ID), super.getUser().getId());
		cu.set(Person.LAST_MODIFIED_TIME, new Date());
		predicates.add(cb.equal(root.get(Person.ID), dto.getId()));

		Predicate[] pre = new Predicate[predicates.size()];
		cu.where(predicates.toArray(pre));
		if (super.entityManager.createQuery(cu).executeUpdate() > 0) {
			return true;
		}

		return false;
	}

	/**
	 * 删除给定的实体
	 * @param dto
	 */
	@Transactional
	public void delete(PersonDTO dto) {
		super.personRepository.delete(this.toModel(dto));
	}

    /**
     * 根据id删除实体
     * @param id
     */
	@Transactional
	public void delete(String id) {
	    super.personRepository.delete(id);
    }

	/**
	 * HQL 更新
	 * @return
	 */
/*	@Transactional
	public int up(){
		String upsql = "UPDATE Person p set p.sysUser.id = :userId";
		Query query = super.entityManager.createQuery(upsql);
		Map<String, Object> params = new HashMap<>();
		params.put("userId", "1");
		super.setParameters(query, params);
		return query.executeUpdate();
	}*/

	public Person updateEntity(Person person) {
		return personRepository.save(person);
	}

	/**
	 * 分页 =》返回 dto
	 * @param dto
	 * @param pageRequest
	 * @return
	 */
	public Page<PersonDTO> findAll(PersonDTO dto, PageRequest pageRequest) {
		Page<Person> pages = super.personRepository.findAll(this.personSpecification(dto), pageRequest);
		return pages.map(this::toDTO);
	}

	public List<PersonDTO> findAll(PersonDTO dto) {
		List<Person> list = super.personRepository.findAll(this.personSpecification(dto));
		if (!CollectionUtils.isEmpty(list)) {
			List<PersonDTO> dtos = Lists.newArrayListWithCapacity(list.size());
			for (Person person : list) {
				dtos.add(this.toDTO(person));
			}
			return dtos;
		}
		return null;
	}


	private PersonDTO toDTO(Person model) {
		PersonDTO dto = new PersonDTO();
		super.copyProperties(model, dto);
		return dto;
	}


	private Person toModel(PersonDTO dto) {
		Person model = new Person();
		super.copyProperties(dto, model);
		return model;
	}

	/**
	 * 动态条件查询
	 * @param dto
	 * @return
	 */
	public Specification<Person> personSpecification(PersonDTO dto){
		return new Specification<Person>() {
			@Override
			public Predicate toPredicate(Root<Person> root,
					CriteriaQuery<?> query, CriteriaBuilder cb) {
				List<Predicate> predicates = new ArrayList<Predicate>();

				if (null != dto.getAge()){
					predicates.add(cb.equal(root.get(Person.AGE), dto.getAge()));
				}
				if (null != dto.getAges() && !dto.getAges().isEmpty()){
					CriteriaBuilder.In<Object> in = cb.in(root.get(Person.AGE));
					for (Integer age : dto.getAges()) {
						in.value(age);
					}
					predicates.add(in);
				}
				if (null != dto.getIds() && !dto.getIds().isEmpty()){
					CriteriaBuilder.In<Object> in = cb.in(root.get(Person.TYPE));
					for (Integer id : dto.getIds()) {
						in.value(id);
					}
					predicates.add(in);
				}
				if (StringUtils.isNotBlank(dto.getId())) {
					predicates.add(cb.like(root.get(Person.ID), dto.getId()));
				}
				/*if (null != dto.getSysUser()){
					Join<Person, SysUser> join = root.join(Person.SYS_USER, JoinType.LEFT);

					if (!StringUtils.isEmpty(dto.getSysUser().getNickname())){
						predicates.add(cb.like(root.get(Person.SYS_USER).get("nickname"), dto.getSysUser().getNickname()));
					}
				}*/
				
				Predicate[] pre = new Predicate[predicates.size()];
				return query.where(predicates.toArray(pre)).getRestriction();
			}
		};
	}

	/**
	 * 保存
	 * @param dto
	 * @return
	 */
	public Person save(PersonDTO dto) {
		return super.personRepository.save(this.toModel(dto));
	}

}
